/*
 * stockboy.h
 *
 *  Created on: May 30, 2011
 *      Author: peskanda
 */
#include "sharedDefinitions.h"
#include "system.h"
#include "stockboy.h"
#include "locks.h"
#include "homedepot.h"
//#include "aisle.h"

StockBoy::StockBoy(int stockBoyIndex,Store* store, Locks* allTheLocks)
											: _stockBoyIndex(stockBoyIndex),
											  _store(store),
											  _allTheLocks(allTheLocks)
{
	//We just created a new stock boy
	ASSERT (_store != NULL);
	ASSERT (_allTheLocks != NULL);
}

void StockBoy::DoWork() {
	//We are currently unavailable
	_allTheLocks->SetStockBoysStatus(_stockBoyIndex, -1);
	Lock* stockRoomLock= _allTheLocks->_stockRoomLock;
	bool justWokeup = true;
	while(true) {
		//lets see if we need to re stock an item
		//_allTheLocks->_stockBoyOrderLock->Acquire();
		int itemIdToBeReStocked = NOT_FOUND;
		//_stockBoyReStockingItem
#ifdef PRINT_EXTRA_LOG_STOCKBOY
		printf("STCOKBOY #%i lets see if any body needs restocking.\n", _stockBoyIndex);
#endif
		Lock* reStockLock = _allTheLocks->_customerWaitingForReStockLock;
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Acquire()\n", _stockBoyIndex);
#endif
		reStockLock->Acquire();
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Acquire done!\n", _stockBoyIndex);
#endif
		for (int i=0; i< MAX_ITEMS; i++)
		{
			if (_allTheLocks->_customersWaitingForRestock[i]>0 && _allTheLocks->_stockBoyReStockingItem[i]==NOT_FOUND) {
				itemIdToBeReStocked = i;
				_allTheLocks->_stockBoyReStockingItem[i] = _stockBoyIndex;
				break;
			}
		}
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Release()\n",  _stockBoyIndex);
#endif
		reStockLock->Release();
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Release() done!\n", _stockBoyIndex);
#endif

		if (itemIdToBeReStocked != NOT_FOUND)
		{
#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i finds out item#%i needs to be re stock\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
			if (!justWokeup)
			{
#ifdef PRINT_OUTPUT_STOCKBOY
				printf("StockBoy [%i] goes back to Stock room for item [%i]\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
			}
			//i need to re stock, lets acquire the storage room
			_allTheLocks->_stockRoomStatusLock->Acquire();
			while (_allTheLocks->_stockBoyIdInStockRoom != NOT_FOUND)
			{
				_allTheLocks->_stockBoysWaitingForStockRoomCV ++;
#ifdef PRINT_OUTPUT_STOCKBOY
				printf("StockBoy [%i] is waiting for StockBoy [%i] to leave the Stock Room.\n", _stockBoyIndex,_allTheLocks->_stockBoyIdInStockRoom);
#endif
				_allTheLocks->_stockRoomCV->Wait(_allTheLocks->_stockRoomStatusLock);
			}
#ifdef PRINT_OUTPUT_STOCKBOY
			printf("StockBoy [%i] is in stock room\n", _stockBoyIndex);
#endif
			_allTheLocks->_stockBoyIdInStockRoom = _stockBoyIndex;
			_allTheLocks->_stockRoomStatusLock->Release();
			//Now we are at stock room, we grab supplies and will get out of the room
			//so other stock boys can use it,
			PickupSuppliesFromStorage(itemIdToBeReStocked);
			//
			// Before leaving stock room we have to tell other stock boys that the next one can enter the stock room
			//
#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i is going to tell everyone he is leaving\n", _stockBoyIndex);
#endif
			_allTheLocks->_stockRoomStatusLock->Acquire();
			_allTheLocks->_stockBoyIdInStockRoom = NOT_FOUND;
			if (_allTheLocks->_stockBoysWaitingForStockRoomCV > 0)
			{
#ifdef PRINT_EXTRA_LOG_STOCKBOY
				printf("STCOKBOY #%i find outs people are waiting for him, signal them to come in.\n", _stockBoyIndex);
#endif
				_allTheLocks->_stockBoysWaitingForStockRoomCV --;
				_allTheLocks->_stockRoomCV->Signal(_allTheLocks->_stockRoomStatusLock);
			}
#ifdef PRINT_OUTPUT_STOCKBOY
			printf("StockBoy [%i] leaves stock room\n", _stockBoyIndex);
#endif
			_allTheLocks->_stockRoomStatusLock->Release();
			//By now we have got the supplies from stock room, locked the item, and can re stock it
#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i is querying the aisle of item#%i\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
			int currentAisleIndex = _store->GetAisleNumber(itemIdToBeReStocked);
			ASSERT(currentAisleIndex >= 0 && currentAisleIndex < MAX_AISLES);
#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i found out the aisle#%i of item#%i\n", _stockBoyIndex,currentAisleIndex, itemIdToBeReStocked);
#endif
			//Lets go to its aisle. Set Status to current aisle
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i Set stock boy status()\n", _stockBoyIndex);
#endif
			_allTheLocks->SetStockBoysStatus(_stockBoyIndex, currentAisleIndex);
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i set stockboy status() Done!\n", _stockBoyIndex);
#endif

#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i is in the aisle#%i\n", _stockBoyIndex, currentAisleIndex);
#endif
			//but first we need to lock the item
			//so no other stock boy or customer can manipulate its values while we are
			//re stocking it.
			Lock* itemLock  = _allTheLocks->_shelfLock[itemIdToBeReStocked];
#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i needs to lock the item#%i first in order to restock it\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i item#%i Lock()\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
			itemLock->Acquire();
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i item#%i Lock() Done!\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
			//Re stock the item
			_store->RestockItem(itemIdToBeReStocked);
#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i ReStcoked the item# %i\n", _stockBoyIndex, itemIdToBeReStocked);
			//let the waiting customers know that the item is available
			printf("STCOKBOY #%i lets wake up people who are waiting for this item#%i\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i item#%i Release()\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
			itemLock->Release();
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i item#%i Release()Done!\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Acquire()\n", _stockBoyIndex);
#endif
			reStockLock->Acquire();
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Acquire() Done!\n", _stockBoyIndex);
#endif
			if (_allTheLocks->_customersWaitingForRestock[itemIdToBeReStocked]>0)
			{
#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i Currently %i customers are waiting for this item. Signal one of them.\n", _stockBoyIndex, _allTheLocks->_customersWaitingForRestock[itemIdToBeReStocked]);
#endif
				_allTheLocks->_customersWaitingForRestock[itemIdToBeReStocked]--;
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i itemWaitCV[%i]->Signal()\n", _stockBoyIndex, itemIdToBeReStocked);
#endif
				_allTheLocks->_itemWaitCV[itemIdToBeReStocked]->Signal(reStockLock);

			}
			_allTheLocks->_stockBoyReStockingItem[itemIdToBeReStocked] = NOT_FOUND;
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Release()\n", _stockBoyIndex);
#endif
			reStockLock->Release();
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i reStockLock->Release() Done!\n", _stockBoyIndex);
#endif

			//_allTheLocks->_stockBoyOrderLock->Release();
			//We are walking in aisle; yield to the coming customers
			//so they have an opportunity to ask their questions.
			for (int i = 0; i < STOCKBOY_DELAY; i++)
				currentThread->Yield();
			//OK. we have re-stocked an item, lets see if there are any customers in this
			//aisle who need help.
			//lets see if any customer has any question in current aisle.
			AnswerQuestionsOfCustomers(currentAisleIndex);
			//lets see if any customer has any question in service area.
			AnswerQuestionsOfCustomers(SERVICE_AREA_LINE);
			#ifdef PRINT_EXTRA_LOG_STOCKBOY
				printf("STCOKBOY #%i is back from service\n", _stockBoyIndex);
			#endif
			justWokeup = false;
		}
		else
		{
			//before we go on break, lets see if any customer has any question waiting in service area.
			AnswerQuestionsOfCustomers(SERVICE_AREA_LINE);
			GoToBreak();
			justWokeup = true;
		}
	}
}

void StockBoy::PickupSuppliesFromStorage(int itemID) {
	//We already have acquired the lock for storage
	//in previous. Section. No additional code required in here because we know we can
	//pick up as many as reuiqred.
	for (int i = 1; i< 10; i++)
		currentThread->Yield();
#ifdef PRINT_OUTPUT_STOCKBOY
	printf("StockBoy [%i] retrieves one new item [%i] from stock room.\n", _stockBoyIndex, itemID);
#endif
}

void StockBoy::AnswerQuestionsOfCustomers(int aisleID) {
	Lock* customersWaiting = _allTheLocks->_customersWaitingInAisleToAskQuestionLock[aisleID];
	Lock* questionLock = _allTheLocks->_customerItemQuestionLock[_stockBoyIndex];
	Lock* answerLock = _allTheLocks->_stockBoyAisleAnswerLock[_stockBoyIndex];
	Lock* stockBoysStatus = _allTheLocks->_stockBoysStatusLock;
	//Check for customers needing help. - Customers will find StockBoys at any aisle, at any time.
	// 									- the Customer has no way of knowing when the stock boy will be ready to help them which
	_allTheLocks->SetStockBoysStatus(_stockBoyIndex, -1);
#ifdef PRINT_EXTRA_LOG_STOCKBOY
		printf("STCOKBOY #%i lets see if any body has any questions\n", _stockBoyIndex);
#endif

#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i customersWaiting->Acquire()\n", _stockBoyIndex);
#endif
	customersWaiting->Acquire();
#ifdef PRINT_LOCKS_STOCKBOY
		printf("STOCKBOY #%i customersWaiting->Acquire() Done!\n", _stockBoyIndex);
#endif
	if (_allTheLocks->_stockBoyIdInAisleToAnswerQuestionMV[aisleID] == NOT_FOUND &&
		_allTheLocks->_customersWaitingInAisleToAskQuestionMV[aisleID] > 0)
	{
		_allTheLocks->_stockBoyIdInAisleToAnswerQuestionMV[aisleID] = _stockBoyIndex;
		while (_allTheLocks->_customersWaitingInAisleToAskQuestionMV[aisleID] > 0 ){
	#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i finds out there are %i customers waiting to ask question in Aisle#%i lock.\n", _stockBoyIndex,_allTheLocks->_customersWaitingInAisleToAskQuestionMV[aisleID],aisleID);
	#endif
			//  There is a customer needing help
			//The stock boy must change their state so that a customer knows that they are ready to help in the customer's aisle
			//_allTheLocks->SetStockBoysStatus(_stockBoyIndex, aisleID + NUM_CUSTOMERS_WAIT_LINES_FOR_STOCKBOYS);
	#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i sets his status to #%i and signals so customers waiting in this aisle realize he is willing to help.\n", _stockBoyIndex,aisleID+NUM_CUSTOMERS_WAIT_LINES_FOR_STOCKBOYS);
	#endif
			#ifdef PRINT_LOCKS_STOCKBOY
				printf("STOCKBOY #%i customersWaiting[customersWaiting][%i]->Signal()\n", _stockBoyIndex, aisleID);
			#endif
			_allTheLocks->_customersWaitingInAisleToAskQuestionCV[aisleID]->Signal(customersWaiting);
			_allTheLocks->_customersWaitingInAisleToAskQuestionMV[aisleID]--;
			//Now the customer can ask his/her question.
			//Lets wait to receive the Item Number
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i question[%i]->Acquire()\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			questionLock->Acquire();
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i question[%i]->Acquire() Done!\n", _stockBoyIndex, _stockBoyIndex);
	#endif

	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i customersWaiting->Release()\n", _stockBoyIndex);
	#endif
			customersWaiting->Release();
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i customersWaiting->Release() Done!\n", _stockBoyIndex);
	#endif
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i question[%i]->Wait()\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			_allTheLocks->_customerItemQuestionCV[_stockBoyIndex]->Wait(questionLock);
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i question[%i]->Wait() Done!\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			int itemIDQuestioned = _allTheLocks->_customerItemQuestionMV[_stockBoyIndex];
			int customerIDasking = _allTheLocks->_customerID_AskingQuestionMV[_stockBoyIndex];
	#ifdef PRINT_OUTPUT_STOCKBOY
			printf("StockBoy [%i] is approached by Customer [%i] for assistance.\n", _stockBoyIndex, customerIDasking);
	#endif
			//Lets answer the question asked
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i Answer[%i]->Acquire()\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			answerLock->Acquire();
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i Answer[%i]->Acquire() Done!\n", _stockBoyIndex, _stockBoyIndex);
	#endif
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i question[%i]->Release()\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			questionLock->Release();
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i question[%i]->Release Done!()\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			int aisleIDAns = _store->GetAisleNumber(itemIDQuestioned);
	#ifdef PRINT_EXTRA_LOG_STOCKBOY
			printf("STCOKBOY #%i the aisle ID for item#%i is #%i\n", _stockBoyIndex, itemIDQuestioned , aisleIDAns);
	#endif
			_allTheLocks->_stockBoyAisleAnswerMV[_stockBoyIndex] = aisleIDAns;
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i answerCV[%i][answerLock]->Signal()\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			_allTheLocks->_stockBoyAisleAnswerCV[_stockBoyIndex]->Signal(answerLock);
	#ifdef PRINT_OUTPUT_STOCKBOY
			printf("StockBoy [%i] gave aisle [%i] to Customer [%i] for item [%i]\n", _stockBoyIndex, aisleIDAns, customerIDasking, itemIDQuestioned);
	#endif
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i customerWaiting->Acquire()\n", _stockBoyIndex);
	#endif
			customersWaiting->Acquire();
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i customerWaiting->Acquire() Done!\n", _stockBoyIndex);
	#endif
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i answer[%i]->Release()\n", _stockBoyIndex, _stockBoyIndex);
	#endif
			answerLock->Release();
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i answer[%i]->Release Done!()\n", _stockBoyIndex, _stockBoyIndex);
	#endif

		}
		_allTheLocks->_stockBoyIdInAisleToAnswerQuestionMV[aisleID] = NOT_FOUND;
	}

	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i customerWaiting->Release()\n", _stockBoyIndex);
	#endif
	customersWaiting->Release();
	#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i customerWaiting->Release() Done!\n", _stockBoyIndex);
	#endif

#ifdef PRINT_LOCKS_STOCKBOY
			printf("STOCKBOY #%i stockBoyStatus->Acquire()\n", _stockBoyIndex);
	#endif
	_allTheLocks->SetStockBoysStatus(_stockBoyIndex, -1);

}


void StockBoy::GoToBreak() {
	//We are currently unavailable
	_allTheLocks->SetStockBoysStatus(_stockBoyIndex, -1);
	Lock* stockBoysBreakLock =_allTheLocks->_stockBoyBreakLock;
	stockBoysBreakLock->Acquire();
	_allTheLocks->_stockBoyOnBreakMV++;
#ifdef PRINT_OUTPUT_STOCKBOY
	printf("StockBoy [%i] is going on break.\n", _stockBoyIndex);
#endif
	_allTheLocks->_stockBoysOnBreakCV->Wait(stockBoysBreakLock);
#ifdef PRINT_OUTPUT_STOCKBOY
	printf("StockBoy [%i] got call from Manager.\n", _stockBoyIndex);
#endif
	stockBoysBreakLock->Release();
	//_allTheLocks->_stockBoyOrderLock->Acquire();
}

int StockBoy::GetIndex()
{
	return _stockBoyIndex;
}
